// @ts-nocheck

import React, { useEffect, useState, useRef, forwardRef, useImperativeHandle } from 'react';
import { Input, message, Spin } from '@inbiz/antd';
import { connect, Observer, observer } from '@formily/react';
import { TextWidget, getMessage } from '@inbiz/react';
import { useEvents } from '@inbiz/utils';
import Error from './error';
import extendApi from './api';
import './style.less';

/* 创建百度api并判断是否用百度定位 */
const createBaiduApi = (idx: string, { turn, api, value, range }, callback) => {
  // 尝试解决https加载http资源报错
  window.HOST_TYPE = '2';
  window.BMAP_PROTOCOL = 'https'; // https导入会有此行代码
  window.BMap_loadScriptTime = new Date().getTime();

  let head = document.getElementsByTagName('head')[0];
  let script = document.getElementById('inbiz-bmap-api');
  if (script) {
    if (value && value.lat && value.lng) {
      /* 解决js加载快于css的问题 */
      setTimeout(() => {
        echoGeo(value, idx, range, turn, callback);
      }, 0);
      return;
    }
    setTimeout(() => {
      getLocation(idx, turn, range, callback);
    });
    return;
  }
  if (!script) {
    script = document.createElement('script');
    (
      script as HTMLScriptElement
    ).src = `https://api.map.baidu.com/getscript?v=2.0&ak=${api}&s=1&services=&t=20220228164532`;
    script.id = 'inbiz-bmap-api1';
    head.appendChild(script);
  }
  script.onload = (script as any).onreadystatechange = function () {
    if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {
      // @ts-ignore
      window.BMap = BMap;
      if (value && value.lat && value.lng) {
        setTimeout(() => {
          echoGeo(value, idx, range, turn, callback);
        }, 0);
        return;
      }
      setTimeout(() => {
        getLocation(idx, turn, range, callback);
      });
    }
  };
};

/* 回显地位值并解析地址 */
const echoGeo = (value, idx, range, turn, callback) => {
  if (!window.map) {
    window.map = {};
  }
  if (!window.marker) {
    window.marker = {};
  }
  if (!window.circle) {
    window.circle = {};
  }
  if (!window.mapClick) {
    window.mapClick = {};
  }
  if (!window.geo) {
    window.geo = {};
  }
  const { lng, lat } = value;
  const point = new window.BMap.Point(lng, lat);
  if (!window.map[idx]) {
    const BMap = window.BMap;
    window.map[idx] = new BMap.Map(idx);
    const convertor = new BMap.Convertor();
    window.map[idx].centerAndZoom(point, 15);
    window.map[idx].enableScrollWheelZoom(true);
    window.map[idx].disableDoubleClickZoom();
  }
  window.mapClick[idx] = (e) => {
    if (!isPointInCircle(e.point, window.circle[idx])) {
      message.info(getMessage('geoLocation.tip'));
      return;
    }
    if (window.geo && window.geo[idx]) {
      window.geo[idx].dispose();
      window.geo[idx] = null;
    }
    window.map[idx].removeOverlay(window.marker[idx]);
    window.marker[idx] = new window.BMap.Marker(e.point);
    window.map[idx].addOverlay(window.marker[idx]);
    window.map[idx].panTo(e.point);
    getAddress(e.point, callback);
  };
  if (turn) {
    if (window.circle[idx]) {
      window.map[idx].removeOverlay(window.circle[idx]);
    }
    window.circle[idx] = new window.BMap.Circle(point, range, {
      fillColor: '#bae3f5',
      fillOpacity: 0.8,
      strokeColor: '#bae3f5',
    });
    window.map[idx].addOverlay(window.circle[idx]);
    window.map[idx].onclick = window.mapClick[idx];
  } else {
    window.map[idx].onclick = null;
  }
  if (window.marker[idx]) {
    window.map[idx].removeOverlay(window.marker[idx]);
  }
  window.marker[idx] = new window.BMap.Marker(point);
  window.map[idx].addOverlay(window.marker[idx]);
  window.map[idx].panTo(point);
  callback({ address: value.address, point }, false);
};

/* 获取浏览器IP定位信息 */
const getLocation = (idx, turn, range, callback) => {
  const options = {
    enableHighAccuracy: true,
    timeout: 5000,
    maximumAge: 0,
  };
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        successCallback(position, idx, turn, range, callback);
      },
      (error) => {
        errorCallback(error, idx, turn, range, callback);
      },
      options,
    );
  } else {
    // alert('浏览器不支持地理定位。')
  }
};

/** 根据经纬度解析地址 */
const getAddress = (point, callback) => {
  const geo = new window.BMap.Geocoder();
  geo.getLocation(point, (result) => {
    if (result) {
      const { lng, lat } = result.point;
      callback({ address: result.address, lng, lat }, true);
    } else {
      callback({
        msg: getMessage('geoLocation.location'),
        value: getMessage('geoLocation.positioning'),
      });
    }
  });
};

/* 输入框输入后定位和选择联想的地址后解析定位 */
const geoInputAddress = (address: string, idx: string, range, turn, callBack) => {
  const localSearch = new window.BMap.LocalSearch(window.map[idx]);
  localSearch.enableAutoViewport();
  localSearch.setSearchCompleteCallback((searchResult) => {
    const info = searchResult && searchResult.getPoi(0);
    if (info) {
      const { point } = info;
      const { lng, lat } = point;
      window.mapClick[idx] = (e) => {
        if (!isPointInCircle(e.point, window.circle[idx])) {
          message.info(getMessage('geoLocation.tip'));
          return;
        }
        if (window.geo && window.geo[idx]) {
          window.geo[idx].dispose();
          window.geo[idx] = null;
        }
        window.map[idx].removeOverlay(window.marker[idx]);
        window.marker[idx] = new window.BMap.Marker(e.point);
        window.map[idx].addOverlay(window.marker[idx]);
        window.map[idx].panTo(e.point);
        getAddress(e.point, callBack, true);
      };
      window.map[idx].centerAndZoom(point, 15);
      if (window.marker[idx]) {
        window.map[idx].removeOverlay(window.marker[idx]);
      }
      if (turn) {
        if (window.circle[idx]) {
          window.circle[idx].setCenter(point);
          window.circle[idx].setRadius(range);
          window.map[idx].onclick = window.mapClick[idx];
        }
      }
      window.marker[idx] = new window.BMap.Marker(point, { title: address });
      window.map[idx].addOverlay(window.marker[idx]);
      callBack({ address, lng, lat });
    } else {
      callback({
        msg: getMessage('geoLocation.location'),
        address: getMessage('geoLocation.positioning'),
      });
    }
  });
  localSearch.search(address);
};

/** 浏览器IP定位成功 */
const successCallback = (position, idx, turn, range, callback) => {
  const { longitude, latitude } = position.coords;
  const transTypesParam = getTransType(position.coords.accuracy);
  const point = new window.BMap.Point(longitude, latitude);
  showMap(point, idx, transTypesParam, turn, range, callback);
};

/** 浏览器IP定位失败 */
const errorCallback = async (error, idx, turn, range, callback) => {
  const geolocation = new window.BMap.Geolocation();
  geolocation.getCurrentPosition(function (r) {
    const transTypesParam = getTransType(r.accuracy);
    // @ts-ignore
    if (this.getStatus() == BMAP_STATUS_SUCCESS) {
      showMap(r.point, idx, transTypesParam, turn, range, callback);
    } else {
      callback({
        msg: getMessage('geoLocation.location'),
        value: getMessage('geoLocation.positioning'),
      });
    }
  });
};

/* 地球半径 */
const EARTHRADIUS = 6370996.81;

/* 度数转成弧度 */
const degreeToRad = (degree) => {
  return (Math.PI * degree) / 180;
};

/* 将v值限定在a,b之间，纬度使用 */
function _getRange(v, a, b) {
  if (a != null) {
    v = Math.max(v, a);
  }
  if (b != null) {
    v = Math.min(v, b);
  }
  return v;
}

/* 将v值限定在a,b之间，经度使用 */
function _getLoop(v, a, b) {
  while (v > b) {
    v -= b - a;
  }
  while (v < a) {
    v += b - a;
  }
  return v;
}

/* 判断点是否在圆内 */
const isPointInCircle = (point, circle) => {
  if (!(point instanceof window.BMap.Point) || !(circle instanceof window.BMap.Circle)) {
    return false;
  }
  const c = circle.getCenter();
  const r = circle.getRadius();
  const dis = getDistance(point, c);
  return dis <= r;
};

/** 计算两点之间的距离,两点坐标必须为经纬度 */
const getDistance = (point1: any, point2: any) => {
  if (!(point1 instanceof window.BMap.Point) || !(point2 instanceof window.BMap.Point)) {
    return 0;
  }
  point1.lng = _getLoop(point1.lng, -180, 180);
  point1.lat = _getRange(point1.lat, -74, 74);
  point2.lng = _getLoop(point2.lng, -180, 180);
  point2.lat = _getRange(point2.lat, -74, 74);
  let x1, x2, y1, y2;
  x1 = degreeToRad(point1.lng);
  y1 = degreeToRad(point1.lat);
  x2 = degreeToRad(point2.lng);
  y2 = degreeToRad(point2.lat);
  return (
    EARTHRADIUS *
    Math.acos(Math.sin(y1) * Math.sin(y2) + Math.cos(y1) * Math.cos(y2) * Math.cos(x2 - x1))
  );
};

/** 展示地图并解析 */
const showMap = (point, idx, transTypesParam, turn, range, callback) => {
  if (!window.map) {
    window.map = {};
  }
  if (!window.marker) {
    window.marker = {};
  }
  if (!window.circle) {
    window.circle = {};
  }
  if (!window.mapClick) {
    window.mapClick = {};
  }
  if (!window.geo) {
    window.geo = {};
  }
  const BMap = window.BMap;
  window.map[idx] = new BMap.Map(idx);
  const convertor = new BMap.Convertor();
  window.map[idx].centerAndZoom(point, 15);
  window.map[idx].enableScrollWheelZoom(true);
  window.map[idx].disableDoubleClickZoom();
  const translateCallback = (data) => {
    if (data.status === 0) {
      let lng = data.points[0].lng;
      let lat = data.points[0].lat;
      const point = new window.BMap.Point(lng, lat);
      window.mapClick[idx] = (e) => {
        if (!isPointInCircle(e.point, window.circle[idx])) {
          message.info(getMessage('geoLocation.tip'));
          return;
        }
        if (window.geo && window.geo[idx]) {
          window.geo[idx].dispose();
          window.geo[idx] = null;
        }
        window.map[idx].removeOverlay(window.marker[idx]);
        window.marker[idx] = new window.BMap.Marker(e.point);
        window.map[idx].addOverlay(window.marker[idx]);
        window.map[idx].panTo(e.point);
        getAddress(e.point, callback);
      };
      if (turn) {
        // const resolution = Math.random();
        // lng += resolution / 100;
        // lat += resolution / 100;
        if (window.circle[idx]) {
          window.map[idx].removeOverlay(window.circle[idx]);
        }
        window.circle[idx] = new window.BMap.Circle(point, range, {
          fillColor: '#bae3f5',
          fillOpacity: 0.8,
          strokeColor: '#bae3f5',
        });
        window.map[idx].addOverlay(window.circle[idx]);
        window.map[idx].onclick = window.mapClick[idx];
      } else {
        window.map[idx].onclick = null;
      }
      if (window.marker[idx]) {
        window.map[idx].removeOverlay(window.marker[idx]);
      }
      window.marker[idx] = new window.BMap.Marker(point);
      window.map[idx].addOverlay(window.marker[idx]);
      window.map[idx].panTo(point);
      getAddress(point, callback);
    }
  };
  convertor.translate([point], transTypesParam, 5, translateCallback);
};

/*
 * 坐标常量说明：
 * COORDINATES_WGS84 = 1, WGS84坐标
 * COORDINATES_WGS84_MC = 2, WGS84的平面墨卡托坐标
 * COORDINATES_GCJ02 = 3，GCJ02坐标
 * COORDINATES_GCJ02_MC = 4, GCJ02的平面墨卡托坐标
 * COORDINATES_BD09 = 5, 百度bd09经纬度坐标
 * COORDINATES_BD09_MC = 6，百度bd09墨卡托坐标
 * COORDINATES_MAPBAR = 7，mapbar地图坐标
 * COORDINATES_51 = 8，51地图坐标
 */
const getTransType = (accuracy) => {
  const type3 = [550, 30];
  if (window.localStorage) {
    const transType = localStorage.getItem('inbiz_type');
    if (transType != null && transType != '') {
      return transType;
    }
  }
  for (let i = 0; i < type3.length; i++) {
    if (type3[i] == accuracy) {
      localStorage.setItem('inbiz_type', '3');
      return 3;
    }
  }
  localStorage.setItem('inbiz_type', '1');
  return 1;
};

/* 加载一次后的hook */
const useDidLocation = (fn, inputs) => {
  const didMountRef = useRef(false);
  useEffect(() => {
    if (didMountRef.current) {
      fn();
    } else {
      didMountRef.current = true;
    }
  }, inputs);
};

/* 生成地图容易唯一ID */
const getId = (key: string) => {
  return (
    'inbiz_' +
    (+new Date() + Math.floor(Math.random() * 10000 + Math.random() * 1000)).toString() +
    '_' +
    key
  );
};

export interface GeoLocationProps {
  /* 是否必填 */
  required: boolean;
  /** 是否启用微调 */
  turn?: boolean;
  /** 是否重新定位 */
  reposition?: boolean;
  /** 百度地图key */
  api?: string;
  /** 扩展样式名称 */
  className?: string;
  /* 地图容器id */
  idx: string;
  /* 微调范围 */
  range: string;
  /* 回显的值 */
  value: {
    address: string;
    lng: number;
    lat: number;
  };
  viewMode?: string;
}

const GeoLocation = forwardRef((props: GeoLocationProps, ref: any) => {
  let { turn, reposition, className, api, callBackEvents, emit, viewMode } = props;

  const [configEvents] = useEvents(callBackEvents, emit);
  if (className) {
    className = [...new Set((className + ' inbiz-geo').split(' '))].join(' ');
  } else {
    className = 'inbiz-geo';
  }
  const [mapId, setMapId] = useState(getId('map'));
  const [data, setData] = useState('');
  const [inputId, setInputId] = useState(getId('input'));
  const [addressName, setAddressName] = useState('');
  const [loading, setLoading] = useState(false);
  const [errorMsg, setErrorMsg] = useState('');
  const getRange = () => {
    let range = props.range ? props.range * 1000 : 1000;
    if (isNaN(Number(range))) {
      range = 1000;
    }
    return range;
  };
  const location = (value) => {
    if (!api) {
      setLoading(false);
      return false
    }
    setLoading(true);
    const range = getRange();
    return createBaiduApi(mapId, { turn, api, range, value }, (result, flag) => {
      setLoading(false);
      emit?.('onload');
      if (result.msg) {
        setAddressName(result.value);
        setErrorMsg(result.msg);
        return;
      }
      setAddressName(result.address);
      setData(result);
      flag && props.onChange(result);
    });
  };
  useEffect(() => {
    // props.value为undefined时，下面的effect会执行，导致两次？
    if (props.value) {
      location(props.value);
    }
  }, []);

  useEffect(() => {
    if (!props.value && props.value !== '') {
      location();
    }
  }, [props.value]);

  useDidLocation(() => {
    if (reposition) {
      location(props.value);
    }
  }, [props.reposition]);
  useDidLocation(() => {
    if (window.circle[mapId]) {
      window.circle[mapId].setRadius(props.range * 1000);
    }
  }, [props.range]);
  useDidLocation(() => {
    location(props.value);
  }, [props.turn]);
  useDidLocation(() => {
    if (window.BMap) {
      const script = document.getElementById('inbiz-bmap-api');
      script?.remove();
    }
    location(props.value);
  }, [props.api]);

  const handleChange = (e) => {
    const val = e.target.value;
    loadAddress(val);
  };

  const loadAddress = (val) => {
    setAddressName(val);
    if (window.circle[mapId]) {
      window.map[mapId].onclick = null;
    }
    if (!val) {
      // @ts-ignore
      props.onChange(val);
      if (window.circle[mapId]) {
        window.circle[mapId].setRadius(0);
      }
      if (window.marker[mapId]) {
        window.map[mapId].removeOverlay(window.marker[mapId]);
        window.marker[mapId] = null;
      }
      return;
    }
    const range = getRange();
    const turn = props.turn;
    geoInputAddress(val, mapId, range, turn, (result, flag) => {
      if (result.msg) {
        props.onChange({ address: getMessage('geoLocation.positioning'), lng: null, lat: null });
        return;
      }
      flag && setAddressName(result.address);
      setData(result);
      props.onChange(result);
    });
    if (!window.geo) {
      window.geo = {};
    }
    if (window.BMap) {
      if (!window.geo[mapId]) {
        window.geo[mapId] = new BMap.Autocomplete({
          input: inputId,
          location: window.map[mapId],
        });
        window.geo[mapId].addEventListener('onconfirm', (e) => {
          const value = e.item.value;
          const address =
            value.province + value.city + value.district + value.street + value.business;
          setAddressName(address);
          geoInputAddress(address, mapId, range, turn, (result, flag) => {
            if (result.msg) {
              props.onChange({
                address: getMessage('geoLocation.positioning'),
                lng: null,
                lat: null,
              });
              setData({ address: getMessage('geoLocation.positioning'), lng: null, lat: null });
              return;
            }
            flag && setAddressName(result.address);
            const { lng, lat } = result;
            setData(result);
            props.onChange(result);
          });
        });
      }
    }
  };

  useImperativeHandle(
    ref,
    () => ({
      ...extendApi(configEvents, { value: data, loadAddress }),
    }),
    [props.value],
  );

  return (
    <Spin spinning={loading}>
      <div className={className}  style={{minHeight: api ? 300 : 150}}>
        <div className="inbiz-geo-wrapper">
          <Observer>
            {() => {
              return viewMode == 'look'&&addressName ? <div>{addressName}</div> : <Input
                  className="inbiz-geo-wrapper-position"
                  value={addressName}
                  placeholder={getMessage('geoLocation.geographicLocation')}
                  readOnly={!reposition}
                  allowClear
                  onChange={handleChange}
                  size="middle"
                />
              


            }}
          </Observer>
         { viewMode != 'look'&&<Input
            style={{ position: 'absolute', zIndex: -999 }}
            id={inputId}
            value={addressName}
            className="inbiz-geo-wrapper-position"
          />}
          {!errorMsg ? (
            <div className="inbiz-geo-wrapper-map" id={mapId}>
              {!api && <div className={className + '-mask'}>
                <p>
                  <TextWidget>geoLocation.config</TextWidget><br/>
                  <TextWidget>geoLocation.details</TextWidget>
                  http://lbsyun.baidu.com/apiconsole/key
                </p>
              </div>}
            </div>
            
          ) : (
            <div className="inbiz-geo-wrapper-error">
              <Error />
              <p>{errorMsg}</p>
            </div>
          )}
        </div>
      </div>
    </Spin>
  );
});

export default connect(GeoLocation);
